#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import functools

from common.const import ExecuteResultEnum, SubJobStatusEnum, DBLogLevel
from common.logger import Logger
from db2.comm.const import Db2CommonConst
from db2.comm.db2_exception import ErrCodeException
from db2.comm.error_code import Db2ErrCode
from db2.comm.util.common_util import Db2CommonUtil
from db2.comm.util.param_util import Db2ParamUtil

LOGGER = Logger().get_logger(filename="db2.log")


def parse_log_param_val(param_names, param_dict):
    log_info_params = list()
    param_dict = param_dict if isinstance(param_dict, dict) else dict()
    param_name_func_map = {
        Db2CommonConst.PARAM_JOB_ID: Db2ParamUtil.get_job_id,
        Db2CommonConst.PARAM_SUB_JOB_ID: Db2ParamUtil.get_sub_job_id,
        Db2CommonConst.PARAM_NODE_IP: Db2ParamUtil.get_node_ip,
    }
    for i in param_names:
        if i in param_name_func_map:
            log_info_params.append(str(param_name_func_map[i](param_dict)))
            continue
        log_info_params.append("")
    return log_info_params


def job_exception_decorator(write_progress=False, is_restore=False, is_pre=False):
    """
    处理备份任务异常返回结果的装饰器
    @param write_progress: 是否写进度信息，True：写；False：不写
    @param is_restore: 是否恢复任务，True：是；False：不是
    @param is_pre: 是否前置任务，True：是；False：不是
    """
    def decorator(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            backup_inst = args[0]
            try:
                return func(*args, **kwargs)
            except ErrCodeException as ex:
                LOGGER.exception(f"Execute task failed, func name: {func.__name__}, error message: {ex.error_message}.")
                if write_progress:
                    log_label, p_names = Db2CommonConst.FUNC_NAME_LABEL_PARAMS_MAP.get(func.__name__, (None, list()))
                    log_info_params = parse_log_param_val(p_names, backup_inst.param_dict)
                    job_detail = Db2CommonUtil.build_log_detail(
                        log_label, log_info_params,
                        err_code=ex.error_code,
                        # 错误码参数
                        log_detail_param=ex.parameter_list,
                        log_level=DBLogLevel.ERROR.value)
                    backup_inst.sub_job_detail.task_status = SubJobStatusEnum.FAILED.value
                    backup_inst.sub_job_detail.log_detail = [job_detail]
                    Db2CommonUtil.proactively_report_progress(backup_inst.pid, backup_inst.sub_job_detail)
                return Db2CommonUtil.build_action_result(
                    code=ExecuteResultEnum.INTERNAL_ERROR.value, body_err=ex.error_code, message=ex.message,
                    err_params=ex.parameter_list)
            except Exception as ex:
                LOGGER.exception(f"Execute task failed. Function Name: {func.__name__}.")
                if write_progress:
                    log_label, p_names = Db2CommonConst.FUNC_NAME_LABEL_PARAMS_MAP.get(func.__name__, (None, list()))
                    log_info_params = parse_log_param_val(p_names, backup_inst.param_dict)
                    job_detail = Db2CommonUtil.build_log_detail(
                        log_label, log_info_params,
                        err_code=Db2ErrCode.OPERATION_FAILED,
                        log_level=DBLogLevel.ERROR.value)
                    backup_inst.sub_job_detail.task_status = SubJobStatusEnum.FAILED.value
                    backup_inst.sub_job_detail.log_detail = [job_detail]
                    Db2CommonUtil.proactively_report_progress(backup_inst.pid, backup_inst.sub_job_detail)
                err_msg = f"Execute task failed. Error Message: {str(ex)}."
                return Db2CommonUtil.build_action_result(
                    code=ExecuteResultEnum.INTERNAL_ERROR.value, body_err=Db2ErrCode.OPERATION_FAILED, message=err_msg)

        return inner

    return decorator


def job_exception_output_decorator(func):
    """处理任务异常输出结果的装饰器"""
    @functools.wraps(func)
    def inner(*args, **kwargs):
        pid = args[0].pid
        try:
            func(*args, **kwargs)
        except ErrCodeException as ex:
            LOGGER.exception(f"Execute task failed, func name: {func.__name__}, error message: {ex.error_message}.")
            Db2CommonUtil.output_action_result(
                pid, ExecuteResultEnum.INTERNAL_ERROR.value, body_err=ex.error_code, message=ex.message,
                err_params=ex.parameter_list)
        except Exception as ex:
            LOGGER.exception(f"Execute task failed. Function Name: {func.__name__}.")
            err_msg = f"Execute task failed. Error Message: {str(ex)}."
            Db2CommonUtil.output_action_result(pid, ExecuteResultEnum.INTERNAL_ERROR.value, message=err_msg)

    return inner
